/* 
建造者模式（Builder Pattern）使用多个简单的对象一步一步构建成一个复杂的对象。这种类型的设计模式属于创建型模式，它提供了一种创建对象的最佳方式。
一个 Builder 类会一步一步构造最终的对象。该 Builder 类是独立于其他对象的。

实现
我们假设一个快餐店的商业案例，其中，一个典型的套餐可以是一个汉堡（Burger）和一杯冷饮（Cold drink）。
汉堡（Burger）可以是素食汉堡（Veg Burger）或鸡肉汉堡（Chicken Burger），它们是包在纸盒中。
冷饮（Cold drink）可以是可口可乐（coke）或百事可乐（pepsi），它们是装在瓶子中。

我们将创建一个表示食物条目（比如汉堡和冷饮）的 Item 接口和实现 Item 接口的实体类，
以及一个表示食物包装的 Packing 接口和实现 Packing 接口的实体类，汉堡是包在纸盒中，冷饮是装在瓶子中。

然后我们创建一个 Meal 类，带有 Item 的 ArrayList 和一个通过结合 Item 来创建不同类型的 Meal 对象的 MealBuilder。
BuilderPatternDemo，我们的演示类使用 MealBuilder 来创建一个 Meal。
 */
/*
建造者模式（Builder Pattern）使用多个简单的对象一步一步构建成一个复杂的对象。这种类型的设计模式属于创建型模式，它提供了一种创建对象的最佳方式。
一个 Builder 类会一步一步构造最终的对象。该 Builder 类是独立于其他对象的。

实现
我们假设一个快餐店的商业案例，其中，一个典型的套餐可以是一个汉堡（Burger）和一杯冷饮（Cold drink）。
汉堡（Burger）可以是素食汉堡（Veg Burger）或鸡肉汉堡（Chicken Burger），它们是包在纸盒中。
冷饮（Cold drink）可以是可口可乐（coke）或百事可乐（pepsi），它们是装在瓶子中。

我们将创建一个表示食物条目（比如汉堡和冷饮）的 Item 接口和实现 Item 接口的实体类，
以及一个表示食物包装的 Packing 接口和实现 Packing 接口的实体类，汉堡是包在纸盒中，冷饮是装在瓶子中。

然后我们创建一个 Meal 类，带有 Item 的 ArrayList 和一个通过结合 Item 来创建不同类型的 Meal 对象的 MealBuilder。
BuilderPatternDemo，我们的演示类使用 MealBuilder 来创建一个 Meal。
 */
#include <iostream>
#include <list>
using namespace std;

// 步骤 1
// 创建一个表示食物条目和食物包装的接口。

class Item
{
public:
	virtual string name() = 0;
	virtual Packing packing() = 0;
	virtual float price() = 0;
};
class Packing
{
public:
	virtual string pack() = 0;
};

// 步骤 2
// 创建实现 Packing 接口的实体类。

class Wrapper : public Packing
{
public:
	string pack()
	{
		cout << "Wrapper" << endl;
	}
};

class Bottle : public Packing
{
public:
	string pack()
	{
		cout << "Bottle" << endl;
	}
};

// 步骤 3
// 创建实现 Item 接口的抽象类，该类提供了默认的功能。

class Burger : public Item
{
public:
	Packing packing()
	{
		return new Wrapper();
	}
};

class ColdDrink : public Item
{
public:
	Packing packing()
	{
		return new Bottle();
	}
};

// 步骤 4
// 创建扩展了 Burger 和 ColdDrink 的实体类。

class VegBurger : public Burger
{
public:
	float price()
	{
		return 25.0f;
	}
	string name()
	{
		return "Veg Burger";
	}
};

class ChickenBurger : public Burger
{
public:
	float price()
	{
		return 50.5f;
	}
	string name()
	{
		return "ChickenBurger";
	}
};

class Coke : public ColdDrink
{
public:
	float price()
	{
		return 2.5f;
	}
	string name()
	{
		return "Coke";
	}
};

class Pepsi : public ColdDrink
{
public:
	float price()
	{
		return 3.5f;
	}
	string name()
	{
		return "Pepsi";
	}
};

// 步骤 5
// 创建一个 Meal 类，菜谱管理上面的 Item 对象。

class Meal
{
public:
	void addItem(Item *item)
	{
		items.push_back(*item);
	}
	float getCost()
	{
		float cost = 0.0f;
		for (Item &item : items)
		{
			cost += item.price();
		}
		return cost;
	}
	void showItems()
	{
		for (Item &item : items)
		{
			cout << "Item : " << item.name();
			cout << ", Packing : " << item->packing()->pack();
			cout << ", Price : " << item.price() << endl;
		}
	}
private:
	list<Item> items = list<Item>();
};

// 步骤 6
// 创建一个 MealBuilder 类，实际的 builder 类负责创建 Meal 对象。

class MealBuilder
{
public:
	Meal prepareVegMeal()		//素菜套餐
	{
		Meal meal = Meal();
		meal.addItem(new VegBurger());
		meal.addItem(new Coke());
		return meal;
	}
	Meal prepareNonVegMeal()	//非素套餐
	{
		Meal meal = Meal();
		meal.addItem(new ChickenBurger());
		meal.addItem(new Pepsi());
		return meal;
	}
};

// 步骤 7
// BuiderPatternDemo 使用 MealBuider 来演示建造者模式（Builder Pattern）。

int main()
{
	MealBuilder mealBuilder = MealBuilder();

	Meal vegMeal = mealBuilder.prepareVegMeal();
	cout << "Veg Meal" << endl;
	vegMeal.showItems();
	cout << "Total Cost: " << vegMeal.getCost() << endl;

	Meal nonVegMeal = mealBuilder.prepareNonVegMeal();
	cout << "Non-Veg Meal" << endl;
	nonVegMeal.showItems();
	cout << "Total Cost: " << nonVegMeal.getCost() << endl;
}
